package com.heu.blood.statistic.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import com.heu.blood.dict.service.DictDepartmentService;
import com.heu.blood.dict.vo.DepartmentDictVo;
import com.heu.blood.statistic.ManyEnum;
import com.heu.blood.statistic.dao.BloodUsagePurposeDao;
import com.heu.blood.statistic.entity.BloodUsagePurpose;
import com.heu.blood.statistic.entity.BloodUsagePurposeFirstVo;
import com.heu.blood.statistic.entity.BloodUsagePurposeShowVo;
import com.heu.blood.statistic.entity.EchartItem;
import com.heu.blood.statistic.service.BloodUsagePurposeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author bearH
 * @date 2023-09-07 15:33
 */
@Service("bloodUsagePurposeService")
public class BloodUsagePurposeServiceImpl extends ServiceImpl<BloodUsagePurposeDao, BloodUsagePurpose> implements BloodUsagePurposeService {
    @Autowired
    private BloodUsagePurposeDao bloodUsagePurposeDao;
    @Autowired
    private DictDepartmentService dictDepartmentService;

//    @Override
//    public List<BloodUsagePurpose> getBloodInformation() {
//        return bloodUsagePurposeDao.selectBloodInformation();
//    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Query<BloodUsagePurpose> query = new Query<>();
        IPage<BloodUsagePurpose> page = query.getPage(params);
        IPage<BloodUsagePurpose> bloodUsagePurposes = bloodUsagePurposeDao.queryPage(page,params);
        return new PageUtils(bloodUsagePurposes);
    }


    @Override
    public BloodUsagePurposeFirstVo getBloodUsageByPurpose() {
        // 1. 获取实际用血量的用途（>0的）
        List<BloodUsagePurposeShowVo> bloodUsageList = bloodUsagePurposeDao.queryTotalBloodUsageByPurpose();

        // 2. 获取所有用途（包括用血量为0的）
        List<BloodUsagePurposeShowVo> allPurposes = bloodUsagePurposeDao.queryAllPurposes();

        // 3. 合并实际用血量到所有用途列表中
        Map<String, BigDecimal> usageMap = bloodUsageList.stream()
                .collect(Collectors.toMap(
                        BloodUsagePurposeShowVo::getUsageName,
                        BloodUsagePurposeShowVo::getBloodCount));

        allPurposes.forEach(vo ->
                vo.setBloodCount(usageMap.getOrDefault(vo.getUsageName(), BigDecimal.ZERO))
        );

        allPurposes.sort((a, b) -> b.getBloodCount().compareTo(a.getBloodCount()));
        // 4. 构建xlist和ylist（包含所有用途）
        List<String> xlist = new ArrayList<>();
        List<BigDecimal> ylist = new ArrayList<>();
        for (BloodUsagePurposeShowVo vo : allPurposes) {
            xlist.add(vo.getUsageName());
            ylist.add(vo.getBloodCount());
        }

        // 5. 构建purposeList（保持原有逻辑：>0的用途+"其他"）
        List<EchartItem> purposeList = new ArrayList<>();

        // 5.1 添加用血量>0的用途
        bloodUsageList.stream()
                .filter(vo -> vo.getBloodCount().compareTo(BigDecimal.ZERO) > 0)
                .forEach(vo -> purposeList.add(new EchartItem(vo.getUsageName(), vo.getBloodCount())));

        // 5.2 添加"其他"项（值为所有0值用途的总和）
        BigDecimal otherTotal = allPurposes.stream()
                .filter(vo -> vo.getBloodCount().compareTo(BigDecimal.ZERO) == 0)
                .map(BloodUsagePurposeShowVo::getBloodCount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        purposeList.add(new EchartItem(ManyEnum.OTHER.value(), otherTotal));

        // 6. 构建返回对象
        BloodUsagePurposeFirstVo vo = new BloodUsagePurposeFirstVo();
        vo.setXlist(xlist);  // 包含所有用途
        vo.setYlist(ylist);  // 包含所有用途（含0值）
        vo.setPurposeList(purposeList); // >0的用途+"其他"

        // 7. 默认加载第一个用途的详情
        if (!allPurposes.isEmpty()) {
            String firstUsage = allPurposes.get(0).getUsageName();
            Map<String, List<EchartItem>> details = getBloodTypeAndDepartmentUsageByPurpose(firstUsage);
            vo.setBloodTypeList(details.get(ManyEnum.ABOLIST.code()));
            vo.setDepartmentList(details.get(ManyEnum.DEPARTMENTLIST.code()));
        }

        return vo;
    }
    @Override
    public Map<String, List<EchartItem>> getBloodTypeAndDepartmentUsageByPurpose(String usageCode) {
        Map<String, List<EchartItem>> responseData = new HashMap<>();

        // 查询所有血型和科室的用血数据
        List<BloodUsagePurposeShowVo> bloodTypeUsageList = bloodUsagePurposeDao.queryBloodUsageByBloodType(usageCode);
        List<BloodUsagePurposeShowVo> departmentUsageList = bloodUsagePurposeDao.queryBloodUsageByDepartment(usageCode);

        if (bloodTypeUsageList == null) {
            bloodTypeUsageList = new ArrayList<>();
        }
        if (departmentUsageList == null) {
            departmentUsageList = new ArrayList<>();
        }

        // 聚合血型数据
        Map<String, BigDecimal> bloodTypeCountMap = new HashMap<>();
        for (BloodUsagePurposeShowVo vo : bloodTypeUsageList) {
            if (vo != null && vo.getBloodType() != null && vo.getBloodCount() != null) {
                bloodTypeCountMap.put(vo.getBloodType(), vo.getBloodCount());
            }
        }

        // 查询所有可能的血型，如果没有用血数据，确保返回 0
        List<String> allBloodTypes = bloodUsagePurposeDao.queryAllBloodTypes();
        if (allBloodTypes != null) {
            for (String bloodType : allBloodTypes) {
                if (bloodType != null) {
                    bloodTypeCountMap.putIfAbsent(bloodType, BigDecimal.ZERO);
                }
            }
        }

        // 处理血型数据
        List<EchartItem> bloodTypeList = bloodTypeCountMap.entrySet().stream()
                .filter(e -> e.getKey() != null && e.getValue() != null)
                .map(e -> new EchartItem(e.getKey(), e.getValue()))
                .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
                .collect(Collectors.toList());

        // 处理血型数据前5名 + 其他
        List<EchartItem> finalBloodTypeList = new ArrayList<>();
        BigDecimal otherBloodTypeTotal = BigDecimal.ZERO;
        int validBloodTypeCount = 0;

        for (EchartItem item : bloodTypeList) {
            if (item != null && item.getValue() != null) {
                if (validBloodTypeCount < 5 && item.getValue().compareTo(BigDecimal.ZERO) > 0) {
                    finalBloodTypeList.add(item);
                    validBloodTypeCount++;
                } else {
                    otherBloodTypeTotal = otherBloodTypeTotal.add(item.getValue());
                }
            }
        }


        if (otherBloodTypeTotal.compareTo(BigDecimal.ZERO) > 0 || validBloodTypeCount < 10) {
            finalBloodTypeList.add(new EchartItem(ManyEnum.OTHER.value(), otherBloodTypeTotal));
        }

        responseData.put(ManyEnum.ABOLIST.code(), finalBloodTypeList);

        // 获取所有科室的树形结构
        List<DepartmentDictVo> departmentTree = dictDepartmentService.getTreeRes();
        if (departmentTree == null) {
            departmentTree = new ArrayList<>();
        }

        // 创建一个映射，用于存储每个科室及其子科室的用血量
        Map<String, BigDecimal> departmentUsageMap = new HashMap<>();

        // 遍历科室树，计算每个一级科室及其子科室的用血量
        for (DepartmentDictVo department : departmentTree) {
            if (department != null) {
                BigDecimal totalUsage = calculateDepartmentUsage(department, departmentUsageList);
                departmentUsageMap.put(department.getCode(), totalUsage);
            }
        }

        // 处理科室数据
        List<EchartItem> departmentList = departmentUsageMap.entrySet().stream()
                .filter(e -> e.getKey() != null && e.getValue() != null)
                .map(e -> new EchartItem(e.getKey(), e.getValue()))
                .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
                .collect(Collectors.toList());

        // 处理科室数据前5名 + 其他
        List<EchartItem> finalDepartmentList = new ArrayList<>();
        BigDecimal otherDepartmentTotal = BigDecimal.ZERO;
        int validDepartmentCount = 0;

        for (EchartItem item : departmentList) {
            if (item != null && item.getValue() != null) {
                if (validDepartmentCount < 5 && item.getValue().compareTo(BigDecimal.ZERO) > 0) {
                    finalDepartmentList.add(item);
                    validDepartmentCount++;
                } else {
                    otherDepartmentTotal = otherDepartmentTotal.add(item.getValue());
                }
            }
        }


        if (otherDepartmentTotal.compareTo(BigDecimal.ZERO) > 0 || validDepartmentCount < 10) {
            finalDepartmentList.add(new EchartItem(ManyEnum.OTHER.value(), otherDepartmentTotal));
        }

        responseData.put(ManyEnum.DEPARTMENTLIST.code(), finalDepartmentList);

        return responseData;
    }

    /**
     * 递归计算指定科室及其子科室的用血量总和
     *
     * @param department           当前科室
     * @param departmentUsageList  用血数据列表
     * @return 当前科室及其子科室的用血量总和
     */
    private BigDecimal calculateDepartmentUsage(DepartmentDictVo department, List<BloodUsagePurposeShowVo> departmentUsageList) {
        BigDecimal totalUsage = BigDecimal.ZERO;

        if (department == null || department.getCode() == null || departmentUsageList == null) {
            return totalUsage;
        }

        // 计算当前科室的用血量
        for (BloodUsagePurposeShowVo usage : departmentUsageList) {
            if (usage != null && usage.getCode() != null && usage.getBloodCount() != null) {
                if (usage.getCode().equals(department.getCode())) {
                    totalUsage = totalUsage.add(usage.getBloodCount());
                }
            }
        }

        // 递归计算子科室的用血量
        List<DepartmentDictVo> children = department.getChildren();
        if (children != null) {
            for (DepartmentDictVo child : children) {
                if (child != null) {
                    totalUsage = totalUsage.add(calculateDepartmentUsage(child, departmentUsageList));
                }
            }
        }

        return totalUsage;
    }
}
